Skip to content

fix: notify() generates iv_nonce and a fresh session_id per call#522

Open
cconstab wants to merge 4 commits into
trunkfrom
fix/notify-iv-nonce-and-session-id
Open

fix: notify() generates iv_nonce and a fresh session_id per call#522
cconstab wants to merge 4 commits into
trunkfrom
fix/notify-iv-nonce-and-session-id

Conversation

@cconstab

@cconstab cconstab commented Jul 2, 2026

Copy link
Copy Markdown
Member

notify() had two defects, both in at_client/atclient.py:

  1. Crashes without a nonce. It read at_key.metadata.iv_nonce and passed it
    straight to aes_encrypt_from_base64; if the caller hadn't set it, AES-CTR raised
    nonce must be bytes-like. Callers had to set metadata.iv_nonce manually.
  2. Shared session_id. The signature default session_id=str(uuid.uuid4()) is
    evaluated once at import, so every notify() without an explicit id reused the same
    id for the process lifetime. The atServer dedups by notification id, so duplicate /
    rapid notifications were silently dropped.

Fix: generate the nonce inside notify() when unset (and store it on the key's
metadata so it travels with the notification for the receiver to decrypt), and default
session_id to None, minting a fresh UUID per call.

Tests: test/notify_test.py — network-free:

  • session_id default is None (regression against the import-time UUID)
  • notify() sets iv_nonce when the key has none (mocked network)

Found while building a production integration on atsdk; both were reproducible in
isolation.

notify() crashed when the AtKey had no iv_nonce ('nonce must be bytes-like'),
forcing callers to set metadata.iv_nonce manually. It also used a signature
default session_id=str(uuid.uuid4()), which is evaluated once at import, so every
notify() without an explicit id reused the same one and the server deduped the
duplicates.

Generate the AES nonce inside notify() when unset (and store it on the key's
metadata so it travels with the notification), and default session_id to None,
generating a fresh UUID per call.

Adds network-free unit tests for both behaviours.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes two long-standing correctness issues in AtClient.notify() by ensuring encrypted notifications always have the required AES-CTR nonce and by preventing reuse of a single import-time session_id. It also adds network-free regression tests covering both behaviors.

Changes:

  • Change notify() to default session_id to None and mint a fresh UUID per call when not provided.
  • Ensure notify() generates and sets metadata.iv_nonce when it is missing, preventing AES-CTR crashes.
  • Add test/notify_test.py to validate the session_id default and nonce generation without requiring network connections.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
at_client/atclient.py Fix notify() session ID default behavior and generate/store an AES-CTR nonce when missing.
test/notify_test.py Add regression tests ensuring session_id is not an import-time UUID and iv_nonce is generated.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread at_client/atclient.py Outdated
Comment thread test/notify_test.py Outdated
@cconstab cconstab requested a review from cpswan July 3, 2026 02:55
…yptionUtil import in test

Addresses review: AES-CTR nonce must not be reused across notify() calls on a reused
AtKey — generate a fresh nonce every call instead of only when unset. Test now also
asserts two calls on the same key produce different nonces. Import EncryptionUtil via
the package (from at_client.util) to match the rest of the suite.
@cconstab

cconstab commented Jul 3, 2026

Copy link
Copy Markdown
Member Author

Thanks @copilot-pull-request-reviewer — both addressed:

  • Nonce per call: notify() now always generates a fresh iv_nonce and sets it on the key metadata for that call, instead of only when unset — no AES-CTR nonce reuse even if the caller reuses an AtKey. Added a test asserting two calls on the same key produce different nonces.
  • Import: switched the test to from at_client.util import EncryptionUtil to match the rest of the suite.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants